package com.air.repo.design.pattern.singleton;

import java.util.Random;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * Place Function on Here:
 *
 * @author yh 2018/7/12 13:36
 * @since: Jdk 1.8
 */
public class Singleton3 {

    private static final Object obj=new Object();
    private /* volatile */ static Singleton3 instance; //申明为 private static volatile

    private Singleton3() {
        try {
            TimeUnit.MILLISECONDS.sleep(1000 * (new Random()).nextInt(18));
        }catch (Exception e){

        }
    }

    public static Singleton3 getInstance() {
        if (instance == null) { //提高性能，不然每次getInstanace都会lock
            //T1,T2....
            synchronized (obj) {//假设18行这里有多个（T1,T2）进入，假设T1先进入，这时20行显得多余，所以直接初始化instance,到23后释放锁，此时T2进来，但是instance不为空了，18行就显得有用了
                if (instance == null) {
                    instance = new Singleton3();
//                    volatile很重要的一个特性没有讲到---禁止重排序
//                    instance = new Singleton3();#4这段代码触发类加载以及实例化对象，因为该过程不是原子性的（1：分配内存，2：初始化对象。（3）将内存空间的地址赋值给对应的引用） 根据Jmm的指令的重排序，实例化过程的执行顺序有可能是 1>3>2，也就是说，因为instance对象没有完全实例化（但是已经有分配地址，instance !=null了），这样线程2就会直接返回这个不完整的uniqueInstance ；使用volatile后，禁止重排序，实例化对象过程只有执行完1>2>3之后uniqueInstance 才会不用为null
                }
            }
        }
        return instance;
    }


    private static Lock lock = new ReentrantLock();

    public static Singleton3 getInstance1() {
        lock.lock();
        if (instance == null) {
            instance = new Singleton3();
        }
        lock.unlock();
        return instance;
    }

}
